package com.fscp.diner.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.fscp.commons.constant.ApiConstant;
import com.fscp.commons.dto.DinerDTO;
import com.fscp.commons.model.domain.ResultInfo;
import com.fscp.commons.model.pojo.Diner;
import com.fscp.commons.model.vo.ShortDinerInfo;
import com.fscp.commons.utils.AssertUtil;
import com.fscp.commons.utils.ResultInfoUtil;
import com.fscp.diner.config.OAuth2ClientConfiguration;
import com.fscp.diner.domain.OAuthDinerInfo;
import com.fscp.diner.mapper.DinerMapper;
import com.fscp.diner.vo.LoginDinerInfo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * 食客服务业务逻辑层
 */
@Service
public class DinerService {

    @Resource
    private RestTemplate restTemplate;
    @Value("${service.name.ms-oauth-server}")
    private String oauthServerName;
    @Resource
    private OAuth2ClientConfiguration oAuth2ClientConfiguration;
    @Resource
    private DinerMapper dinerMapper;
    @Resource
    private SendVerifyCodeService sendVerifyCodeService;


    /**
     * 校验手机号是否注册
     * @param phone
     */
    public void checkPhoneIsRegistered(String phone) {
        // 健壮性处理
        AssertUtil.isNotEmpty(phone, "手机号不能为空!");

        Diner diner = dinerMapper.selectDinerByPhone(phone);
        AssertUtil.isTrue(diner == null, "该手机号未注册!");
        // 这里 isValid 映射需要注意 Mybatis 驼峰映射配置设置
        AssertUtil.isTrue(diner.getIsValid() == 0, "该用户已锁定/注销，请先解锁!");
    }

    /**
     * 用户注册
     *
     * @param dinerDTO
     * @param path
     * @return
     */
    public ResultInfo register(DinerDTO dinerDTO, String path) {
        // 参数非空校验
        String username = dinerDTO.getUsername();
        AssertUtil.isNotEmpty(username, "请输入用户名!");
        String password = dinerDTO.getPassword();
        AssertUtil.isNotEmpty(password, "请输入密码!");
        String phone = dinerDTO.getPhone();
        AssertUtil.isNotEmpty(phone, "请输入手机号!");
        String  verifyCode = dinerDTO.getVerifyCode();
        AssertUtil.isNotEmpty(verifyCode, "请输入验证码!");
        // 验证码一致性校验
        String code = sendVerifyCodeService.getCodeByPhone(phone);          // 获取验证码
        AssertUtil.isNotEmpty(code, "验证码已过期，请重新发送!");       // 验证是否过期
        AssertUtil.isTrue(!dinerDTO.getVerifyCode().equals(code), "验证码错误，请重新输入!");
        // 验证用户名是否已注册
        Diner diner = dinerMapper.selectDinerByUsername(username);
        AssertUtil.isTrue(diner != null, "该用户名已存在，请重新输入!");
        // 密码加密并注册
        dinerDTO.setPassword(DigestUtil.md5Hex(password.trim()));
        dinerMapper.saveDiner(dinerDTO);
        // 自动登录
        return signIn(username.trim(), password.trim(), path);
    }

    /**
     * 登录
     *
     * @param account       账号：用户名/手机号/邮箱
     * @param password      密码
     * @param path          请求路径
     * @return resultInfo   公共响应对象
     */
    public ResultInfo signIn(String account, String password, String path) {
        //  参数校验
        AssertUtil.isNotEmpty(account, "请输入登录账号");
        AssertUtil.isNotEmpty(password, "请输入登录密码");

        // 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        // 构建请求体（请求参数）
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("username", account);
        body.add("password", password);
        body.setAll(BeanUtil.beanToMap(oAuth2ClientConfiguration));

        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);

        // 设置 Authorization
        restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(oAuth2ClientConfiguration.getClientId(),
                oAuth2ClientConfiguration.getSecret()));
        // 发送请求
        ResponseEntity<ResultInfo> result = restTemplate.postForEntity(oauthServerName + "oauth/token",
                entity, ResultInfo.class);

        // 处理返回结果
        AssertUtil.isTrue(result.getStatusCode() != HttpStatus.OK, "登录失败");
        ResultInfo resultInfo = result.getBody();
        if (resultInfo.getCode() != ApiConstant.SUCCESS_CODE) {
            // 登录失败
            resultInfo.setData(resultInfo.getMessage());
            return resultInfo;
        }
        // 这里的 data 是一个 LinkedHashMap 转成了域对象 OAuthDinerInfo
        OAuthDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap) resultInfo.getData(),
                new OAuthDinerInfo(), false);
        // 根据业务需求返回试图对象
        LoginDinerInfo loginDinerInfo = new LoginDinerInfo();
        loginDinerInfo.setToken(dinerInfo.getAccessToken());
        loginDinerInfo.setAvatarUrl(dinerInfo.getAvatarUrl());
        loginDinerInfo.setNickname(dinerInfo.getNickname());

        // 返回请求成功结果
        return ResultInfoUtil.buildSuccess(path, loginDinerInfo);
    }


    /**
     * 根据 ids 查询食客信息
     *
     * @param ids 主键 id，多个以逗号分隔，逗号之间不用空格
     * @return
     */
    public List<ShortDinerInfo> findByIds(String ids) {
        AssertUtil.isNotEmpty(ids);
        String[] idArr = ids.split(",");
        List<ShortDinerInfo> dinerInfos = dinerMapper.findByIds(idArr);
        return dinerInfos;
    }

}
